package com.jie.netty.im;


import com.jie.constants.ChannelAttrKey;
import com.jie.constants.IMRedisKey;
import com.jie.netty.im.tactics.DisconnectionHandler;
import com.jie.netty.im.tactics.HeartbeatTimeoutHandler;
import com.jie.netty.im.tactics.factory.DisconnectionFactory;
import com.jie.netty.im.tactics.factory.HeartbeatTimeoutFactory;
import com.jie.netty.im.tactics.impl.LoginDisconnectionHandler;
import com.jie.netty.im.tactics.impl.LoginHeartbeatTimeoutHandler;
import com.jie.netty.im.tactics.impl.RoomDisconnectionHandler;
import com.jie.netty.im.tactics.impl.RoomHeartbeatTimeoutHandler;
import com.jie.netty.model.IMSendInfo;
import com.jie.netty.processor.AbstractMessageProcessor;
import com.jie.netty.processor.ProcessorFactory;
import com.jie.netty.type.IMCmdType;
import com.jie.utils.SpringContextHolder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * WebSocket 长连接下 文本帧的处理器
 * 实现浏览器发送文本回写
 * 浏览器连接状态监控
 */
@Slf4j
public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
    /**
     * 读取到消息后进行处理
     *
     * @param ctx      channel上下文
     * @param sendInfo 发送消息
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, IMSendInfo sendInfo) {
        // 创建处理器进行处理
        AbstractMessageProcessor processor = ProcessorFactory.createProcessor(Objects.requireNonNull(IMCmdType.fromCode(sendInfo.getCmd())));
        processor.process(ctx, processor.transForm(sendInfo.getData()));
    }

    /**
     * 出现异常的处理 打印报错日志
     *
     * @param ctx   channel上下文
     * @param cause 异常信息
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(cause.getMessage());
        //关闭上下文
        //ctx.close();
    }

    /**
     * 监控浏览器上线
     *
     * @param ctx channel上下文
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        log.info(ctx.channel().id().asLongText() + "连接");
    }

    /**
     *  当前用户下线则触发
     * @param ctx
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        AttributeKey<String> publicInfoAttr = AttributeKey.valueOf(ChannelAttrKey.PUBLIC_INFO);
        String publicInfo = ctx.channel().attr(publicInfoAttr).get();
        DisconnectionHandler disconnectionHandler = DisconnectionFactory.createDisconnectionHandler(publicInfo);
        if (disconnectionHandler!= null) {
            disconnectionHandler.handleDisconnection(ctx);
        }
    }
    /**
     *  心跳一定时间未收到，则触发
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                AttributeKey<String> publicInfoAttr = AttributeKey.valueOf(ChannelAttrKey.PUBLIC_INFO);
                String publicInfo = ctx.channel().attr(publicInfoAttr).get();
                HeartbeatTimeoutHandler heartbeatTimeoutHandler = HeartbeatTimeoutFactory.createHeartbeatTimeoutHandler(publicInfo);
                if (heartbeatTimeoutHandler!=null) {
                    heartbeatTimeoutHandler.handleTimeout(ctx);
                }
                ctx.channel().close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}